package com.jingdianjichi.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.google.gson.Gson;
import com.jingdianjichi.auth.common.enums.AuthUserStatusEnum;
import com.jingdianjichi.auth.common.enums.IsDeleteEnum;
import com.jingdianjichi.auth.domain.constants.AuthConstant;
import com.jingdianjichi.auth.domain.convert.AuthUserBOConverter;
import com.jingdianjichi.auth.domain.entity.AuthUserBO;
import com.jingdianjichi.auth.domain.redis.RedisUtil;
import com.jingdianjichi.auth.domain.service.AuthUserDomainService;
import com.jingdianjichi.auth.infra.basic.entity.*;
import com.jingdianjichi.auth.infra.basic.mapper.AuthUserDao;
import com.jingdianjichi.auth.infra.basic.service.AuthRolePermissionService;
import com.jingdianjichi.auth.infra.basic.service.AuthRoleService;
import com.jingdianjichi.auth.infra.basic.service.AuthUserRoleService;
import com.jingdianjichi.auth.infra.basic.service.AuthUserService;
import com.jingdianjichi.auth.infra.basic.service.impl.AuthPermissionServiceImpl;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    @Resource
    private AuthUserService authUserService;
    @Resource
    private AuthRoleService authRoleService;
    @Resource
    private AuthUserRoleService authUserRoleService;
    @Resource
    private AuthRolePermissionService authRolePermissionService;
    //自主如避免失误失效
    @Lazy
    @Autowired
    private AuthUserDomainService authUserDomainService;

    //与缓存做同步
    @Resource
    private RedisUtil redisUtil;

    private String authPermissionPrefix="auth:permission";
    private String authRolePrefix="auth:role";

    //加盐
    private String salt="dingshao666";
    @Autowired
    private AuthPermissionServiceImpl authPermissionService;

    /**
     * 用户注册
     * @param authUserBO
     * @return
     */
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        //注册即往表中插入信息
        AuthUser authUser = AuthUserBOConverter.Instance.convertBOToEntity(authUserBO);
        authUser.setIsDeleted(IsDeleteEnum.UN_DELETED.getCode());
        if (StringUtils.isNotBlank(authUser.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(),salt));
        }
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        Integer count = authUserService.insert(authUser);

        //建立一个初步的角色关联
        AuthRole authRole=new AuthRole();
        authRole.setRoleKey(AuthConstant.NORMAL_USER);
        AuthRole authResult=authRoleService.queryByCondition(authRole);
        //拿到插入主键
        Long roleId=authResult.getId();
        Long userId=authUser.getId();
        //往用户角色关联表插入数据
        AuthUserRole authUserRole=new AuthUserRole();
        authUserRole.setRoleId(roleId);
        authUserRole.setUserId(userId);
        authUserRole.setIsDeleted(IsDeleteEnum.UN_DELETED.getCode());
        authUserRoleService.insert(authUserRole);
        //TODO 建立初步角色关联，后续同步到redis中
        //先建立用户名字key，根据用户名字key建立他所含角色表和权限表
        String RoleKey=redisUtil.buildKey(authRolePrefix,authUser.getUserName());
        List<AuthRole> authRoles=new ArrayList<>();
        authRoles.add(authResult);
        redisUtil.set(RoleKey,new Gson().toJson(authRoles));
        //根据用户添加的角色表中的id获取它所包含的权限
        //所以需要根据角色权限表通过roleid获取permissionid,再根据permissionid查permission表
        //将查到的所有权限放入redis
        AuthRolePermission authRolePermission=new AuthRolePermission();
        authRolePermission.setRoleId(roleId);
        authRolePermission.setIsDeleted(IsDeleteEnum.UN_DELETED.getCode());
        List<AuthRolePermission> authRolePermissions=authRolePermissionService.queryByCondition(authRolePermission);
        //根据关联表获取permissionid
        List<Long> permissionIds = authRolePermissions.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        //根据permissionid获取权限
        List<AuthPermission> authPermissions=authPermissionService.queryByIds(permissionIds);
        String PermissionKey=redisUtil.buildKey(authPermissionPrefix,authUser.getUserName());
        redisUtil.set(PermissionKey,new Gson().toJson(authPermissions));

        return count > 0;
    }

    /**
     * 更新用户
     * @param authUserBO
     * @return
     */
    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.Instance.convertBOToEntity(authUserBO);
        Integer count= authUserService.update(authUser);
        return count>0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.Instance.convertBOToEntity(authUserBO);
        authUser.setIsDeleted(IsDeleteEnum.UN_DELETED.getCode());
        Integer count= authUserService.update(authUser);
        return count>0;
    }

    @Override
    @Transactional
    public SaTokenInfo doLogin(String validCode) {
        //用户登录逻辑，目前打算是分几步走
        //1.之前微信对接公众号用户后将对应用户的验证码已经存到了redis中，验证码为键，用户openid作为值放入redis中，
        //2.然后根据前端登录传入的code验证码判断redis是否存在
        //存在则直接取出用户id同时调用上面注册方法，同时用aop取出代理进行执行，防止注册事务失效
        //不存在返回错误信息
        String s = redisUtil.get(validCode);
        if (s==null){
            return null;
        }


        AuthUserBO authUserBO=new AuthUserBO();
        authUserBO.setUserName(s);
        //拿到代理对象存在则调用注册接口
        authUserDomainService.register(authUserBO);
        StpUtil.login(s);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return tokenInfo;

    }

}
